#include "SNNegImageReader.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QDir>
#include "opencv2\imgproc\imgproc.hpp"
#include "opencv2\highgui\highgui.hpp"
#include "opencv2\core\core.hpp"
//-------------------------------------------------------------
SNNegImageReader::SNNegImageReader()
{
	Src.create(0, 0, CV_8UC1);
	Img.create(0, 0, CV_8UC1);
	Point = cv::Point(0, 0);
	Offset = cv::Point(0, 0);
	Scale = 1.0f;
	ScaleFactor = 1.4142135623730950488016887242097f;
	StepFactor = 0.5f;
}
//-------------------------------------------------------------

SNNegImageReader::~SNNegImageReader()
{
}
//-------------------------------------------------------------

bool SNNegImageReader::Create(const QString filename, cv::Size win_size)
{
	bool res = false;

	QFile dirs_file_name(filename);
	if (dirs_file_name.open(QIODevice::ReadOnly))
	{
		QTextStream ts(&dirs_file_name);

		QStringList neg_dirs = ts.readAll().split("\r\n");

		for (auto dir_name : neg_dirs)
		{
			QStringList filters;
			filters << "*.bmp";
			filters << "*.jpg";
			filters << "*.png";

			QDir dir(dir_name);

			QStringList files = dir.entryList(filters);

			for (auto f : files)
			{
				QString path = dir_name + "/" + f;
				Filenames.push_back(path);
			}
		}

		WinSize = win_size;
		Last = 0;
		Round = 0;

		res = true;

		dirs_file_name.close();
	}

	return res;
}
//-------------------------------------------------------------

bool SNNegImageReader::Get(cv::Mat& img)
{
	CV_Assert(!img.empty());
	CV_Assert(img.type() == CV_8UC1);
	CV_Assert(img.cols == WinSize.width);
	CV_Assert(img.rows == WinSize.height);

	if (img.empty())
	if (!NextImage())
		return false;

	cv::Mat mat(WinSize.height, WinSize.width, CV_8UC1,
		(void*)(img.data + Point.y * img.step + Point.x * img.elemSize()), img.step);
	
	mat.copyTo(img);

	if ((int)(Point.x + (1.0F + StepFactor) * WinSize.width) < img.cols)
	{
		Point.x += (int)(StepFactor * WinSize.width);
	}
	else
	{
		Point.x = Offset.x;
		if ((int)(Point.y + (1.0F + StepFactor) * WinSize.height) < img.rows)
		{
			Point.y += (int)(StepFactor * WinSize.height);
		}
		else
		{
			Point.y = Offset.y;
			Scale *= ScaleFactor;
			if (Scale <= 1.0F)
			{
				cv::resize(Src, Img, cv::Size((int)(Scale * Src.cols), (int)(Scale * Src.rows)));
			}
			else
			{
				if (!NextImage())
					return false;
			}
		}
	}
	return true;
}
//-------------------------------------------------------------

bool SNNegImageReader::NextImage()
{
	cv::Point offset = cv::Point(0, 0);

	size_t count = Filenames.size();

	for (size_t i = 0; i < count; i++)
	{
		Src = cv::imread(Filenames[Last++].toStdString().c_str(), 0);

		if (Src.cols < WinSize.width || Src.rows < WinSize.height)
		{
			resize(Src, Src, WinSize);
		}

		Round += Last / count;
		Round = Round % (WinSize.width * WinSize.height);
		Last %= count;

		if (Src.empty())
			continue;
		
		offset.x = std::min((int)Round % WinSize.width, Src.cols - WinSize.width);
		offset.y = std::min((int)Round / WinSize.width, Src.rows - WinSize.height);
		if (!Src.empty() && Src.type() == CV_8UC1
			&& Offset.x >= 0 && Offset.y >= 0)
			break;
	}

	if (Src.empty())
		return false; // no appropriate image
	
	Point = Offset = offset;
	Scale = std::max(((float)WinSize.width + Point.x) / ((float)Src.cols),
		((float)WinSize.height + Point.y) / ((float)Src.rows));

	cv::Size sz((int)(Scale * Src.cols + 0.5F), (int)(Scale * Src.rows + 0.5F));
	cv::resize(Src, Img, sz);
	return true;
}
//-------------------------------------------------------------